// Package timerUtils
// @File: timed_task.go
// @Description: 定时任务管理
// @Author: YaoRuiQi
// @Date: 2025/9/9 14:35
package timerUtils

import (
	"sync"

	"github.com/robfig/cron/v3"
)

type Timer interface {
	// FindCronNameList 寻找所有CronName
	FindCronNameList() []string
	// AddTaskByFuncWithSecond 添加Task 方法形式以秒的形式加入
	AddTaskByFuncWithSecond(cronName string, spec string, fun func(), taskName string, option ...cron.Option) (cron.EntryID, error) // 添加Task Func以秒的形式加入
	// AddTaskByJobWithSeconds 添加Task 接口形式以秒的形式加入
	AddTaskByJobWithSeconds(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error)
	// AddTaskByFunc 通过函数的方法添加任务
	AddTaskByFunc(cronName string, spec string, task func(), taskName string, option ...cron.Option) (cron.EntryID, error)
	// AddTaskByJob 通过接口的方法添加任务 要实现一个带有 Run方法的接口触发
	AddTaskByJob(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error)
	// FindCron 获取对应taskName的cron 可能会为空
	FindCron(cronName string) (*taskManager, bool)
	// StartCron 指定cron开始执行
	StartCron(cronName string)
	// StopCron 指定cron停止执行
	StopCron(cronName string)
	// FindTask 查找指定cron下的指定task
	FindTask(cronName string, taskName string) (*task, bool)
	// RemoveTask 根据id删除指定cron下的指定task
	RemoveTask(cronName string, id int)
	// RemoveTaskByName 根据taskName删除指定cron下的指定task
	RemoveTaskByName(cronName string, taskName string)
	// Clear 清理掉指定cronName
	Clear(cronName string)
	// Close 停止所有的cron
	Close()
}

type task struct {
	EntryID  cron.EntryID
	Spec     string
	TaskName string
}

type taskManager struct {
	corn  *cron.Cron
	tasks map[cron.EntryID]*task
}

// timer 定时任务管理
type timer struct {
	cronList map[string]*taskManager
	sync.Mutex
}

// AddTaskByFunc
//
//	@Description: 通过函数的方法添加任务，如果指定的cronName不存在，则创建新的cron实例
//	@receiver t *timer 定时任务管理器
//	@param cronName string cron名称，用于标识不同的定时任务组
//	@param spec string 时间表达式，定义任务执行的时间规则
//	@param fun func() 需要执行的任务函数
//	@param taskName string 任务名称，用于标识具体的任务
//	@param option ...cron.Option cron配置选项，可以用来定制cron的行为
//	@return cron.EntryID 返回添加任务的唯一标识符
//	@return error 如果添加任务过程中出现错误，则返回错误信息
func (t *timer) AddTaskByFunc(cronName string, spec string, fun func(), taskName string, option ...cron.Option) (cron.EntryID, error) {
	t.Lock()
	defer t.Unlock()
	if _, ok := t.cronList[cronName]; !ok {
		tasks := make(map[cron.EntryID]*task)
		t.cronList[cronName] = &taskManager{
			corn:  cron.New(option...),
			tasks: tasks,
		}
	}
	id, err := t.cronList[cronName].corn.AddFunc(spec, fun)
	t.cronList[cronName].corn.Start()
	t.cronList[cronName].tasks[id] = &task{
		EntryID:  id,
		Spec:     spec,
		TaskName: taskName,
	}
	return id, err
}

// AddTaskByFuncWithSecond
//
//	@Description: 通过函数的方法添加任务，时间单位为秒，如果指定的cronName不存在，则创建新的cron实例
//	@receiver t *timer 定时任务管理器
//	@param cronName string cron名称，用于标识不同的定时任务组
//	@param spec string 时间表达式，定义任务执行的时间规则（以秒为单位）
//	@param fun func() 需要执行的任务函数
//	@param taskName string 任务名称，用于标识具体的任务
//	@param option ...cron.Option cron配置选项，可以用来定制cron的行为，并会自动添加WithSeconds选项
//	@return cron.EntryID 返回添加任务的唯一标识符
//	@return error 如果添加任务过程中出现错误，则返回错误信息
func (t *timer) AddTaskByFuncWithSecond(cronName string, spec string, fun func(), taskName string, option ...cron.Option) (cron.EntryID, error) {
	t.Lock()
	defer t.Unlock()
	option = append(option, cron.WithSeconds())
	if _, ok := t.cronList[cronName]; !ok {
		tasks := make(map[cron.EntryID]*task)
		t.cronList[cronName] = &taskManager{
			corn:  cron.New(option...),
			tasks: tasks,
		}
	}
	id, err := t.cronList[cronName].corn.AddFunc(spec, fun)
	t.cronList[cronName].corn.Start()
	t.cronList[cronName].tasks[id] = &task{
		EntryID:  id,
		Spec:     spec,
		TaskName: taskName,
	}
	return id, err
}

// AddTaskByJob
//
//	@Description: 通过接口的方法添加任务，如果指定的cronName不存在，则创建新的cron实例
//	@receiver t *timer 定时任务管理器
//	@param cronName string cron名称，用于标识不同的定时任务组
//	@param spec string 时间表达式，定义任务执行的时间规则
//	@param job interface{ Run() } 需要执行的任务接口，必须实现Run方法
//	@param taskName string 任务名称，用于标识具体的任务
//	@param option ...cron.Option cron配置选项，可以用来定制cron的行为
//	@return cron.EntryID 返回添加任务的唯一标识符
//	@return error 如果添加任务过程中出现错误，则返回错误信息
func (t *timer) AddTaskByJob(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error) {
	t.Lock()
	defer t.Unlock()
	if _, ok := t.cronList[cronName]; !ok {
		tasks := make(map[cron.EntryID]*task)
		t.cronList[cronName] = &taskManager{
			corn:  cron.New(option...),
			tasks: tasks,
		}
	}
	id, err := t.cronList[cronName].corn.AddJob(spec, job)
	t.cronList[cronName].corn.Start()
	t.cronList[cronName].tasks[id] = &task{
		EntryID:  id,
		Spec:     spec,
		TaskName: taskName,
	}
	return id, err
}

// AddTaskByJobWithSeconds
//
//	@Description: 通过接口的方法添加任务，时间单位为秒，如果指定的cronName不存在，则创建新的cron实例
//	@receiver t *timer 定时任务管理器
//	@param cronName string cron名称，用于标识不同的定时任务组
//	@param spec string 时间表达式，定义任务执行的时间规则（以秒为单位）
//	@param job interface{ Run() } 需要执行的任务接口，必须实现Run方法
//	@param taskName string 任务名称，用于标识具体的任务
//	@param option ...cron.Option cron配置选项，可以用来定制cron的行为，并会自动添加WithSeconds选项
//	@return cron.EntryID 返回添加任务的唯一标识符
//	@return error 如果添加任务过程中出现错误，则返回错误信息
func (t *timer) AddTaskByJobWithSeconds(cronName string, spec string, job interface{ Run() }, taskName string, option ...cron.Option) (cron.EntryID, error) {
	t.Lock()
	defer t.Unlock()
	option = append(option, cron.WithSeconds())
	if _, ok := t.cronList[cronName]; !ok {
		tasks := make(map[cron.EntryID]*task)
		t.cronList[cronName] = &taskManager{
			corn:  cron.New(option...),
			tasks: tasks,
		}
	}
	id, err := t.cronList[cronName].corn.AddJob(spec, job)
	t.cronList[cronName].corn.Start()
	t.cronList[cronName].tasks[id] = &task{
		EntryID:  id,
		Spec:     spec,
		TaskName: taskName,
	}
	return id, err
}

// FindCron
//
//	@Description: 获取对应cronName的cron实例，如果存在则返回taskManager及true，否则返回nil及false
//	@receiver t *timer 定时任务管理器
//	@param cronName string 需要查找的cron名称
//	@return *taskManager 返回查找到的taskManager指针，可能为nil
//	@return bool 返回是否找到对应的cron实例
func (t *timer) FindCron(cronName string) (*taskManager, bool) {
	t.Lock()
	defer t.Unlock()
	v, ok := t.cronList[cronName]
	return v, ok
}

// FindTask
//
//	@Description: 根据cronName和taskName查找指定的任务，如果找到则返回task指针及true，否则返回nil及false
//	@receiver t *timer 定时任务管理器
//	@param cronName string cron名称，用于标识不同的定时任务组
//	@param taskName string 任务名称，用于标识具体的任务
//	@return *task 返回查找到的task指针，可能为nil
//	@return bool 返回是否找到对应的任务
func (t *timer) FindTask(cronName string, taskName string) (*task, bool) {
	t.Lock()
	defer t.Unlock()
	v, ok := t.cronList[cronName]
	if !ok {
		return nil, ok
	}
	for _, t2 := range v.tasks {
		if t2.TaskName == taskName {
			return t2, true
		}
	}
	return nil, false
}

// FindCronNameList
//
//	@Description: 获取所有已注册的cron名称列表
//	@receiver t *timer 定时任务管理器
//	@return []string 返回当前所有cron名称组成的切片
func (t *timer) FindCronNameList() []string {
	t.Lock()
	defer t.Unlock()
	var cronList []string
	for k := range t.cronList {
		cronList = append(cronList, k)
	}
	return cronList
}

// StartCron
//
//	@Description: 启动指定名称的cron任务调度器，如果该cron存在则启动，否则不执行任何操作
//	@receiver t *timer 定时任务管理器
//	@param cronName string 需要启动的cron名称
func (t *timer) StartCron(cronName string) {
	t.Lock()
	defer t.Unlock()
	if v, ok := t.cronList[cronName]; ok {
		v.corn.Start()
	}
}

// StopCron
//
//	@Description: 停止指定名称的cron任务调度器，如果该cron存在则停止，否则不执行任何操作
//	@receiver t *timer 定时任务管理器
//	@param cronName string 需要停止的cron名称
func (t *timer) StopCron(cronName string) {
	t.Lock()
	defer t.Unlock()
	if v, ok := t.cronList[cronName]; ok {
		v.corn.Stop()
	}
}

// RemoveTask
//
//	@Description: 根据cronName和任务ID删除指定的任务，如果该cron存在且任务存在则删除，否则不执行任何操作
//	@receiver t *timer 定时任务管理器
//	@param cronName string cron名称，用于标识不同的定时任务组
//	@param id int 需要删除的任务ID
func (t *timer) RemoveTask(cronName string, id int) {
	t.Lock()
	defer t.Unlock()
	if v, ok := t.cronList[cronName]; ok {
		v.corn.Remove(cron.EntryID(id))
		delete(v.tasks, cron.EntryID(id))
	}
}

// RemoveTaskByName
//
//	@Description: 根据cronName和taskName删除指定的任务，如果该cron存在且任务存在则删除，否则不执行任何操作
//	@receiver t *timer 定时任务管理器
//	@param cronName string cron名称，用于标识不同的定时任务组
//	@param taskName string 需要删除的任务名称
func (t *timer) RemoveTaskByName(cronName string, taskName string) {
	fTask, ok := t.FindTask(cronName, taskName)
	if !ok {
		return
	}
	t.RemoveTask(cronName, int(fTask.EntryID))
}

// Clear
//
//	@Description: 清理掉指定cronName的cron实例，如果该cron存在则停止并删除，否则不执行任何操作
//	@receiver t *timer 定时任务管理器
//	@param cronName string 需要清理的cron名称
func (t *timer) Clear(cronName string) {
	t.Lock()
	defer t.Unlock()
	if v, ok := t.cronList[cronName]; ok {
		v.corn.Stop()
		delete(t.cronList, cronName)
	}
}

// Close
//
//	@Description: 停止所有cron任务调度器，并释放相关资源
//	@receiver t *timer 定时任务管理器
func (t *timer) Close() {
	t.Lock()
	defer t.Unlock()
	for _, v := range t.cronList {
		v.corn.Stop()
	}
}

// NewTimerTask
//
//	@Description: 创建一个新的定时任务管理器实例
//	@return Timer 返回一个实现了Timer接口的定时任务管理器
func NewTimerTask() Timer {
	return &timer{cronList: make(map[string]*taskManager)}
}
